Wayland: Implement KDE's SSD protocol
authorDrew DeVault <sir@cmpwn.com>
Sat, 29 Apr 2017 00:35:51 +0000 (20:35 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Thu, 26 Oct 2017 19:51:56 +0000 (15:51 -0400)
If the compositor prefers server-side decorations and the client doesn't
customize the title bar, we disable client-side decorations and let the
compositor know. Otherwise, we continue to use client-side decorations.

Signed-off-by: Drew DeVault <sir@cmpwn.com>
https://bugzilla.gnome.org/show_bug.cgi?id=781909

gdk/wayland/gdkdisplay-wayland.c
gdk/wayland/gdkdisplay-wayland.h
gdk/wayland/gdkwaylanddisplay.h
gdk/wayland/gdkwaylandwindow.h
gdk/wayland/gdkwindow-wayland.c
gdk/wayland/meson.build
gdk/wayland/protocol/server-decoration.xml [new file with mode: 0644]
gtk/gtkwindow.c

index 2154e5101e83f4a1724de9fcc1bbaf894a915ca4..ab1aa72a02093fd42cab1226c0a0d42d668b9d36 100644 (file)
@@ -49,6 +49,7 @@
 #include "tablet-unstable-v2-client-protocol.h"
 #include <wayland/xdg-shell-unstable-v6-client-protocol.h>
 #include <wayland/xdg-foreign-unstable-v1-client-protocol.h>
+#include <wayland/server-decoration-client-protocol.h>
 
 /**
  * SECTION:wayland_interaction
@@ -336,6 +337,35 @@ static const struct wl_shm_listener wl_shm_listener = {
   wl_shm_format
 };
 
+static void
+server_decoration_manager_default_mode (void                                          *data,
+                                        struct org_kde_kwin_server_decoration_manager *manager,
+                                        uint32_t                                       mode)
+{
+  g_assert (mode <= ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER);
+  const char *modes[] = {
+    [ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE]   = "none",
+    [ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT] = "client",
+    [ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER] = "server",
+  };
+  GdkWaylandDisplay *display_wayland = data;
+  g_debug ("Compositor prefers decoration mode '%s'", modes[mode]);
+  display_wayland->server_decoration_mode = mode;
+}
+
+static const struct org_kde_kwin_server_decoration_manager_listener server_decoration_listener = {
+  .default_mode = server_decoration_manager_default_mode
+};
+
+gboolean
+gdk_wayland_display_prefers_ssd (GdkDisplay *display)
+{
+  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+  if (display_wayland->server_decoration_manager)
+    return display_wayland->server_decoration_mode == ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER;
+  return FALSE;
+}
+
 static void
 gdk_registry_handle_global (void               *data,
                             struct wl_registry *registry,
@@ -459,6 +489,15 @@ gdk_registry_handle_global (void               *data,
         wl_registry_bind (display_wayland->wl_registry, id,
                           &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1);
     }
+  else if (strcmp (interface, "org_kde_kwin_server_decoration_manager") == 0)
+    {
+      display_wayland->server_decoration_manager =
+        wl_registry_bind (display_wayland->wl_registry, id,
+                          &org_kde_kwin_server_decoration_manager_interface, 1);
+      org_kde_kwin_server_decoration_manager_add_listener (display_wayland->server_decoration_manager,
+                                                           &server_decoration_listener,
+                                                           display_wayland);
+    }
   else
     handled = FALSE;
 
index 3f53108a158c90012239b109c014d5f45bae2bdc..37083c757620c873feff46eafde1ea140f0dffcd 100644 (file)
@@ -32,6 +32,7 @@
 #include <gdk/wayland/xdg-shell-unstable-v6-client-protocol.h>
 #include <gdk/wayland/xdg-foreign-unstable-v1-client-protocol.h>
 #include <gdk/wayland/keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h>
+#include <gdk/wayland/server-decoration-client-protocol.h>
 
 #include <glib.h>
 #include <gdk/gdkkeys.h>
@@ -79,6 +80,7 @@ struct _GdkWaylandDisplay
   struct zxdg_exporter_v1 *xdg_exporter;
   struct zxdg_importer_v1 *xdg_importer;
   struct zwp_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit;
+  struct org_kde_kwin_server_decoration_manager *server_decoration_manager;
 
   GList *async_roundtrips;
 
@@ -106,6 +108,8 @@ struct _GdkWaylandDisplay
   int data_device_manager_version;
   int gtk_shell_version;
 
+  uint32_t server_decoration_mode;
+
   struct xkb_context *xkb_context;
 
   GdkWaylandSelection *selection;
index f4b51c82d118c4691500a0ec1f5828b0209a1eda..c77da4f85607f56a6f002c18d31cbbbee148365f 100644 (file)
@@ -57,6 +57,8 @@ GDK_AVAILABLE_IN_3_22
 void                    gdk_wayland_display_set_startup_notification_id (GdkDisplay *display,
                                                                          const char *startup_id);
 
+gboolean                gdk_wayland_display_prefers_ssd         (GdkDisplay *display);
+
 G_END_DECLS
 
 #endif /* __GDK_WAYLAND_DISPLAY_H__ */
index 628204ff4a2c2fe8437f502d8be81b1d45227952..61c52dae69c3af38bd3176e4711e80d7cbeba0f4 100644 (file)
@@ -81,6 +81,8 @@ GDK_AVAILABLE_IN_3_22
 gboolean                 gdk_wayland_window_set_transient_for_exported (GdkWindow *window,
                                                                         char      *parent_handle_str);
 
+void gdk_wayland_window_announce_csd                        (GdkWindow *window);
+
 G_END_DECLS
 
 #endif /* __GDK_WAYLAND_WINDOW_H__ */
index 157d41da6132a782e8e9abd6632a448102f3d868..298435ec7a7564f30d683377565a9f8a2e3a2d53 100644 (file)
@@ -117,6 +117,7 @@ struct _GdkWindowImplWayland
     struct wl_egl_window *egl_window;
     struct wl_egl_window *dummy_egl_window;
     struct zxdg_exported_v1 *xdg_exported;
+    struct org_kde_kwin_server_decoration *server_decoration;
   } display_server;
 
   EGLSurface egl_surface;
@@ -1663,6 +1664,21 @@ window_anchor_to_gravity (GdkGravity rect_anchor)
           ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
 }
 
+void
+gdk_wayland_window_announce_csd (GdkWindow *window)
+{
+  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
+  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+  if (!display_wayland->server_decoration_manager)
+    return;
+  impl->display_server.server_decoration =
+    org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager,
+                                                  impl->display_server.wl_surface);
+  if (impl->display_server.server_decoration)
+    org_kde_kwin_server_decoration_request_mode (impl->display_server.server_decoration,
+                                                ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT);
+}
+
 static GdkWindow *
 get_real_parent_and_translate (GdkWindow *window,
                                gint      *x,
index bab68ac30e75914dbb474721406d52159c9e06e6..845667408f4947b8eff0d45a4dd5cfbb136f9c18 100644 (file)
@@ -54,7 +54,8 @@ proto_sources = [
   ['xdg-shell', 'unstable', 'v6', ],
   ['xdg-foreign', 'unstable', 'v1', ],
   ['tablet', 'unstable', 'v2', ],
-  [ 'keyboard-shortcuts-inhibit', 'unstable', 'v1', ],
+  ['keyboard-shortcuts-inhibit', 'unstable', 'v1', ],
+  ['server-decoration', 'stable' ],
 ]
 
 gdk_wayland_gen_headers = []
diff --git a/gdk/wayland/protocol/server-decoration.xml b/gdk/wayland/protocol/server-decoration.xml
new file mode 100644 (file)
index 0000000..8bc106c
--- /dev/null
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="server_decoration">
+  <copyright><![CDATA[
+    Copyright (C) 2015 Martin Gräßlin
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  ]]></copyright>
+  <interface  name="org_kde_kwin_server_decoration_manager" version="1">
+      <description summary="Server side window decoration manager">
+        This interface allows to coordinate whether the server should create
+        a server-side window decoration around a wl_surface representing a
+        shell surface (wl_shell_surface or similar). By announcing support
+        for this interface the server indicates that it supports server
+        side decorations.
+      </description>
+      <request name="create">
+        <description summary="Create a server-side decoration object for a given surface">
+            When a client creates a server-side decoration object it indicates
+            that it supports the protocol. The client is supposed to tell the
+            server whether it wants server-side decorations or will provide
+            client-side decorations.
+
+            If the client does not create a server-side decoration object for
+            a surface the server interprets this as lack of support for this
+            protocol and considers it as client-side decorated. Nevertheless a
+            client-side decorated surface should use this protocol to indicate
+            to the server that it does not want a server-side deco.
+        </description>
+        <arg name="id" type="new_id" interface="org_kde_kwin_server_decoration"/>
+        <arg name="surface" type="object" interface="wl_surface"/>
+      </request>
+      <enum name="mode">
+            <description summary="Possible values to use in request_mode and the event mode."/>
+            <entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither server nor client-side. An example is a popup surface which should not be decorated."/>
+            <entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the surface and the client."/>
+            <entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface into a decoration frame."/>
+      </enum>
+      <event name="default_mode">
+          <description summary="The default mode used on the server">
+              This event is emitted directly after binding the interface. It contains
+              the default mode for the decoration. When a new server decoration object
+              is created this new object will be in the default mode until the first
+              request_mode is requested.
+
+              The server may change the default mode at any time.
+          </description>
+          <arg name="mode" type="uint" summary="The default decoration mode applied to newly created server decorations."/>
+      </event>
+  </interface>
+  <interface name="org_kde_kwin_server_decoration" version="1">
+      <request name="release" type="destructor">
+        <description summary="release the server decoration object"/>
+      </request>
+      <enum name="mode">
+            <description summary="Possible values to use in request_mode and the event mode."/>
+            <entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither server nor client-side. An example is a popup surface which should not be decorated."/>
+            <entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the surface and the client."/>
+            <entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface into a decoration frame."/>
+      </enum>
+      <request name="request_mode">
+          <description summary="The decoration mode the surface wants to use."/>
+          <arg name="mode" type="uint" summary="The mode this surface wants to use."/>
+      </request>
+      <event name="mode">
+          <description summary="The new decoration mode applied by the server">
+              This event is emitted directly after the decoration is created and
+              represents the base decoration policy by the server. E.g. a server
+              which wants all surfaces to be client-side decorated will send Client,
+              a server which wants server-side decoration will send Server.
+
+              The client can request a different mode through the decoration request.
+              The server will acknowledge this by another event with the same mode. So
+              even if a server prefers server-side decoration it's possible to force a
+              client-side decoration.
+
+              The server may emit this event at any time. In this case the client can
+              again request a different mode. It's the responsibility of the server to
+              prevent a feedback loop.
+          </description>
+          <arg name="mode" type="uint" summary="The decoration mode applied to the surface by the server."/>
+      </event>
+  </interface>
+</protocol>
index 1e87600b98c239ca281ea80fcf64c97fcd2ffab5..68de62e940d77723a4c4469f295753f3c59e10f7 100644 (file)
@@ -6047,7 +6047,10 @@ gtk_window_should_use_csd (GtkWindow *window)
 
 #ifdef GDK_WINDOWING_WAYLAND
   if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
-    return TRUE;
+    {
+      GdkDisplay *gdk_display = gtk_widget_get_display (GTK_WIDGET (window));
+      return !gdk_wayland_display_prefers_ssd (gdk_display);
+    }
 #endif
 
 #ifdef GDK_WINDOWING_MIR
@@ -6894,6 +6897,11 @@ gtk_window_realize (GtkWidget *widget)
   if (!priv->decorated || priv->client_decorated)
     gdk_window_set_decorations (gdk_window, 0);
 
+#ifdef GDK_WINDOWING_WAYLAND
+  if (priv->client_decorated && GDK_IS_WAYLAND_WINDOW (gdk_window))
+    gdk_wayland_window_announce_csd (gdk_window);
+#endif
+
   if (!priv->deletable)
     gdk_window_set_functions (gdk_window, GDK_FUNC_ALL | GDK_FUNC_CLOSE);